<template>
    <div class="uploader-file" :class="status" :status="status">
        <slot
            :file="file"
            :list="list"
            :status="status"
            :paused="paused"
            :error="error"
            :response="response"
            :average-speed="averageSpeed"
            :formated-average-speed="formatedAverageSpeed"
            :current-speed="currentSpeed"
            :is-complete="isComplete"
            :is-uploading="isUploading"
            :size="size"
            :formated-size="formatedSize"
            :uploaded-size="uploadedSize"
            :progress="progress"
            :progressing-class="progressingClass"
            :time-remaining="timeRemaining"
            :formated-time-remaining="formatedTimeRemaining"
            :type="type"
            :extension="extension"
            :file-category="fileCategory"
        >
            <div class="uploader-file-info">
                <div class="file-name">
                    <i class="el-icon-loading" v-if="status == 'uploading'"></i>
                    <i class="el-icon-error" v-else-if="status == 'error'"></i>
                    <!-- <i class="el-icon-paperclip" v-else-if="status == 'success'"></i> -->
                    <i class="el-icon-success" v-else-if="status == 'success'"></i>

                    <span class="name">{{file.name || file.fileName}}</span>
                </div>
                <div class="operate" style="line-height: initial">
                    <i class="el-icon-video-pause" v-if="status == 'uploading'" @click="pause"></i>
                    <i class="el-icon-video-play" v-else-if="status == 'paused'" @click="resume"></i>
                    <i class="el-icon-refresh-right" v-else-if="status == 'error'" @click="retry"></i>
                    <i class="el-icon-close" @click="remove"></i>
                </div>
            </div>
            <div class="progress">
                <el-progress :percentage="percentage" status="exception" color="#FF0000" v-if="status == 'error'"></el-progress>
                <el-progress :percentage="percentage" status="success" color="#009900" v-else-if="status == 'success'"></el-progress>
                <el-progress :percentage="percentage" color="#007AFF" v-else></el-progress>
            </div>
        </slot>
    </div>
</template>

<script>
import Uploader from "simple-uploader.js";
import events from "./common/file-events";
import { secondsToStr } from "./common/utils";

const COMPONENT_NAME = "uploader-file";

export default {
    name: COMPONENT_NAME,
    props: {
        file: {
            type: Object,
            default() {
                return {};
            },
        },
        list: {
            type: Boolean,
            default: false,
        },
    },
    data() {
        return {
            response: null,
            paused: false,
            error: false,
            averageSpeed: 0,
            currentSpeed: 0,
            isComplete: false,
            isUploading: false,
            size: 0,
            formatedSize: "",
            uploadedSize: 0,
            progress: 0,
            timeRemaining: 0,
            type: "",
            extension: "",
            progressingClass: "",
        };
    },
    computed: {
        fileCategory() {
            const extension = this.extension;
            const isFolder = this.file.isFolder;
            let type = isFolder ? "folder" : "unknown";
            const categoryMap = this.file.uploader.opts.categoryMap;
            const typeMap = categoryMap || {
                image: ["gif", "jpg", "jpeg", "png", "bmp", "webp"],
                video: [
                    "mp4",
                    "m3u8",
                    "rmvb",
                    "avi",
                    "swf",
                    "3gp",
                    "mkv",
                    "flv",
                ],
                audio: ["mp3", "wav", "wma", "ogg", "aac", "flac"],
                document: [
                    "doc",
                    "txt",
                    "docx",
                    "pages",
                    "epub",
                    "pdf",
                    "numbers",
                    "csv",
                    "xls",
                    "xlsx",
                    "keynote",
                    "ppt",
                    "pptx",
                ],
            };
            Object.keys(typeMap).forEach((_type) => {
                const extensions = typeMap[_type];
                if (extensions.indexOf(extension) > -1) {
                    type = _type;
                }
            });
            return type;
        },
        percentage() {
            const progress = Math.floor(this.progress * 100);
            return progress;
        },
        formatedAverageSpeed() {
            return `${Uploader.utils.formatSize(this.averageSpeed)} / s`;
        },
        progressStatus() {
            if (this.status == "error") {
                return "exception";
            } else {
                return "";
            }
        },
        status() {
            const isUploading = this.isUploading;
            const isComplete = this.isComplete;
            const isError = this.error;
            const paused = this.paused;
            if (isComplete) {
                return "success";
            } else if (isError) {
                return "error";
            } else if (isUploading) {
                return "uploading";
            } else if (paused) {
                return "paused";
            } else {
                return "waiting";
            }
        },
        statusText() {
            const status = this.status;
            const fileStatusText = this.file.uploader.fileStatusText;
            let txt = status;
            if (typeof fileStatusText === "function") {
                txt = fileStatusText(status, this.response);
            } else {
                txt = fileStatusText[status];
            }
            return txt || status;
        },
        formatedTimeRemaining() {
            const timeRemaining = this.timeRemaining;
            const file = this.file;
            if (
                timeRemaining === Number.POSITIVE_INFINITY ||
                timeRemaining === 0
            ) {
                return "";
            }
            let parsedTimeRemaining = secondsToStr(timeRemaining);
            const parseTimeRemaining = file.uploader.opts.parseTimeRemaining;
            if (parseTimeRemaining) {
                parsedTimeRemaining = parseTimeRemaining(
                    timeRemaining,
                    parsedTimeRemaining
                );
            }
            return parsedTimeRemaining;
        },
    },
    watch: {
        status(newStatus, oldStatus) {
            if (
                oldStatus &&
                newStatus === "uploading" &&
                oldStatus !== "uploading"
            ) {
                this.tid = setTimeout(() => {
                    this.progressingClass = "uploader-file-progressing";
                }, 200);
            } else {
                clearTimeout(this.tid);
                this.progressingClass = "";
            }
        },
    },
    methods: {
        _actionCheck() {
            this.paused = this.file.paused;
            this.error = this.file.error;
            this.isUploading = this.file.isUploading();
        },
        pause() {
            this.file.pause();
            this._actionCheck();
            this._fileProgress();
            this.$emit('pause')
        },
        resume() {
            this.file.resume();
            this._actionCheck();
            this.$emit('resume')
        },
        remove() {
            this.file.cancel();
        },
        retry() {
            this.file.retry();
            this._actionCheck();
        },
        processResponse(message) {
            let res = message;
            try {
                res = JSON.parse(message);
            } catch (e) {}
            this.response = res;
        },
        fileEventsHandler(event, args) {
            const rootFile = args[0];
            const file = args[1];
            const target = this.list ? rootFile : file;
            if (this.file === target) {
                if (this.list && event === "fileSuccess") {
                    this.processResponse(args[2]);
                    return;
                }
                this[`_${event}`].apply(this, args);
            }
        },
        _fileProgress() {
            this.progress = this.file.progress();
            this.averageSpeed = this.file.averageSpeed;
            this.currentSpeed = this.file.currentSpeed;
            this.timeRemaining = this.file.timeRemaining();
            this.uploadedSize = this.file.sizeUploaded();
            this._actionCheck();
        },
        _fileSuccess(rootFile, file, message) {
            if (rootFile) {
                this.processResponse(message);
            }
            this._fileProgress();
            this.error = false;
            this.isComplete = true;
            this.isUploading = false;
        },
        _fileComplete() {
            this._fileSuccess();
        },
        _fileError(rootFile, file, message) {
            this._fileProgress();
            this.processResponse(message);
            this.error = true;
            this.isComplete = false;
            this.isUploading = false;
        },
    },
    mounted() {
        const staticProps = ["paused", "error", "averageSpeed", "currentSpeed"];
        const fnProps = [
            "isComplete",
            "isUploading",
            {
                key: "size",
                fn: "getSize",
            },
            {
                key: "formatedSize",
                fn: "getFormatSize",
            },
            {
                key: "uploadedSize",
                fn: "sizeUploaded",
            },
            "progress",
            "timeRemaining",
            {
                key: "type",
                fn: "getType",
            },
            {
                key: "extension",
                fn: "getExtension",
            },
        ];
        staticProps.forEach((prop) => {
            this[prop] = this.file[prop];
        });
        fnProps.forEach((fnProp) => {
            if (typeof fnProp === "string") {
                this[fnProp] = this.file[fnProp]();
            } else {
                this[fnProp.key] = this.file[fnProp.fn]();
            }
        });

        const handlers = (this._handlers = {});
        const eventHandler = (event) => {
            handlers[event] = (...args) => {
                this.fileEventsHandler(event, args);
            };
            return handlers[event];
        };
        events.forEach((event) => {
            this.file.uploader.on(event, eventHandler(event));
        });
    },
    destroyed() {
        events.forEach((event) => {
            this.file.uploader.off(event, this._handlers[event]);
        });
        this._handlers = null;
    },
};
</script>

<style lang="scss">
.uploader-file {
    position: relative;
    width: 440px;
    background: #e6f7ff;
    border-radius: 2px;
    border: 1px solid #d4f0ff;
    padding: 8px 12px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    margin-top: 8px;

    &.success {
        .el-icon-loading,
        .el-icon-paperclip,
        .el-icon-close,
        .el-icon-view {
            color: #007aff;
        }
    }
}
.uploader-file[status="waiting"] .uploader-file-pause,
.uploader-file[status="uploading"] .uploader-file-pause {
    display: block;
}
.uploader-file[status="paused"] .uploader-file-resume {
    display: block;
}
.uploader-file[status="error"] .uploader-file-retry {
    display: block;
}
.uploader-file[status="success"] .uploader-file-remove {
    display: none;
}
.uploader-file[status="error"] .uploader-file-progress {
    background: #ffe0e0;
}
.uploader-file-progress {
    position: absolute;
    width: 100%;
    height: 100%;
    background: #e2eeff;
    transform: translateX(-100%);
}
.uploader-file-progressing {
    transition: all 0.4s linear;
}
.uploader-file-info {
    position: relative;
    z-index: 1;
    height: 100%;
    overflow: hidden;
    display: flex;
    justify-content: space-between;
    .file-name {
        font-size: 12px;
        color: #333;
        display: flex;
        align-items: center;
        line-height: initial;
        .name {
            width: 300px;
            margin-left: 8px;
            display: inline-block;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .el-icon-error {
            color: #ff0000;
        }
        .el-icon-success {
            color: #009900;
        }
    }
    .el-icon-close,
    .el-icon-refresh-right {
        color: #999999;
        &:hover {
            color: #007aff;
        }
    }
    i {
        font-size: 14px;
    }
    .el-icon-video-pause,
    .el-icon-video-play,
    .el-icon-close,
    .el-icon-refresh-right,
    .el-icon-view {
        color: #999;
        cursor: pointer;
    }
}
.uploader-file-info:hover {
    background-color: rgba(240, 240, 240, 0.2);
}
.uploader-file-info i,
.uploader-file-info em {
    font-style: normal;
}
.uploader-file-name,
.uploader-file-size,
.uploader-file-meta,
.uploader-file-status,
.uploader-file-actions {
    float: left;
    position: relative;
    height: 100%;
}
.uploader-file-name {
    width: 45%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    text-indent: 14px;
}
.uploader-file-icon {
    width: 24px;
    height: 24px;
    display: inline-block;
    vertical-align: top;
    margin-top: 13px;
    margin-right: 8px;
}
.uploader-file-icon::before {
    content: "📃";
    display: block;
    height: 100%;
    font-size: 24px;
    line-height: 1;
    text-indent: 0;
}
.uploader-file-icon[icon="folder"]::before {
    content: "📂";
}
.uploader-file-icon[icon="image"]::before {
    content: "📊";
}
.uploader-file-icon[icon="video"]::before {
    content: "📹";
}
.uploader-file-icon[icon="audio"]::before {
    content: "🎵";
}
.uploader-file-icon[icon="document"]::before {
    content: "📋";
}
.uploader-file-size {
    width: 13%;
    text-indent: 10px;
}
.uploader-file-meta {
    width: 8%;
}
.uploader-file-status {
    width: 24%;
    text-indent: 20px;
}
.uploader-file-actions {
    width: 10%;
}
.uploader-file-actions > span {
    display: none;
    float: left;
    width: 16px;
    height: 16px;
    margin-top: 16px;
    margin-right: 10px;
    cursor: pointer;
    background: url("")
        no-repeat 0 0;
}
.uploader-file-actions > span:hover {
    background-position-x: -21px;
}
.uploader-file-actions .uploader-file-pause {
    background-position-y: 0;
}
.uploader-file-actions .uploader-file-resume {
    background-position-y: -17px;
}
.uploader-file-actions .uploader-file-retry {
    background-position-y: -53px;
}
.uploader-file-actions .uploader-file-remove {
    display: block;
    background-position-y: -34px;
}
::v-deep .el-progress__text {
    display: none;
}
::v-deep .el-progress-bar {
    margin-right: 0 !important;
    padding-right: 0 !important;
}
</style>
